
#ifndef _STANDART_NODES_
#define _STANDART_NODES_

#include "Runtime.Low/Threads.h"
#include "Node.h"

namespace ttg_internal
{
	namespace pipeline
	{
		//Node, which represents unique start of pipeline.
		//Sends incoming data to all outputs.
		template <class Type>
		class StartOfPipeline :public ttg::pipeline::Node<Type, Type>
		{
			protected:
				//Just adds data to collection.
				virtual void process(Type data)
				{ sendNext(data); }
			public:
				//Creates start for pipeline.
				inline StartOfPipeline()
					:Node("__StartOfPipeline")
				{ /*nothing*/ }
		};
		//Node, which gatheres all incoming data and returns them via getGatheredData().
		//Will be used as real end of pipeline.
		template <class InType>
		class EndOfPipeline :public ttg::pipeline::Node<InType, bool>
		{
			private:
				std::vector<InType> gathered;		//all gathered data
				//ttg::threads::SlowEvent on_finish;
				ttg::threads::SlowEvent on_finish;
			protected:
				//Just adds data to collection.
				virtual void process(InType data)
				{ gathered.push_back(data); }
				//Cleares data, that were gathered at previous iteration.
				virtual void onBegin()
				{ gathered.clear(); }
				//Wakes root thread.
				virtual void onEnd()
				{ on_finish.rise(); }
			public:
				//Creates end for pipeline.
				inline EndOfPipeline()
					:Node("__EndOfPipeline", true)
				{ gathered.reserve(512); }
				//Returns event for root thread.
				inline ttg::threads::ThreadEvent &getOnFinish()
				{ return on_finish; }
				//Returns all gathered data.
				inline std::vector<InType> &getGatheredData()
				{ return gathered; }
		};
		//Node, which represents unique start of one of subpipelines.
		//Sends incoming data to all outputs.
		template <class Type>
		class StartOfSubPipeline :public ttg::pipeline::ContextedNode<Type, Type>
		{
			protected:
				//Just adds data to collection.
				virtual void process(ttg::pipeline::ContextID ID, Type data)
				{ sendNext(data); }
			public:
				//Creates start for pipeline.
				inline StartOfSubPipeline()
					:ContextedNode("__StartOfSubPipeline")
				{ /*nothing*/ }
		};
		//Node, which gatheres all incoming data, differs them by context ID and
		//returns them via getGatheredData(). Will be used as real end of one of subpipelines.
		template <class InType>
		class EndOfSubPipeline :public ttg::pipeline::ContextedNode<InType, bool>
		{
			private:
				ttg::pipeline::ContextMap<
					std::pair<std::vector<InType>,
							  ttg::structures::Loopback<std::vector<InType> *>>> gathered;
			protected:
				//Just adds data to collection.
				virtual void process(ttg::pipeline::ContextID ID, InType data)
				{
					//Fix me!
					gathered[getIContext().getDataBuffer().getContextID()].first.push_back(data);
				}
				//Cleares data ad ID-context, that were gathered at previous iteration.
				virtual void onBegin(ttg::pipeline::ContextID ID)
				{
					std::pair<std::vector<InType>,
							  ttg::structures::Loopback<std::vector<InType> *>> &ref
						= gathered[ID];
					ref.first.clear();
					ref.second.clear();
				}
				//Notifies about end of iteration at ID-context.
				virtual void onEnd(ttg::pipeline::ContextID ID)
				{
					std::pair<std::vector<InType>,
							  ttg::structures::Loopback<std::vector<InType> *>> &ref
						= gathered[ID];
					ref.second.notify(&ref.first);
				}
			public:
				//Creates end for pipeline.
				inline EndOfSubPipeline()
					:ContextedNode("__EndOfSubPipeline", true)
				{ /*nothing*/ }
				//Returns loopback for end of iteration (for required context).
				inline ttg::structures::Loopback<std::vector<InType> *> 
					&onFinish(ttg::pipeline::ContextID ID)
				{ return gathered[ID].second; }
		};
	}
}

#endif